﻿using System;
using System.Linq;
using Noria.Web.MyMSDN.Models;

namespace Noria.Web.MyMSDN
{
    internal class SimpleStatistics : IStatistics
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private static readonly log4net.ILog alog = log4net.LogManager.GetLogger("Noria.Audit");

        private readonly object sync = new object();
        private readonly string indicator;

        private History occurrence;

        public SimpleStatistics(string indicator)
        {
            this.indicator = indicator;
            Init();
        }

        private void Init()
        {
            using (var db = new MmContext())
            {
                occurrence = new History
                    {
                        Start = DateTime.UtcNow,
                        Initiator = indicator,
                        Status = HistoryStatus.InProcessing.ToString()
                    };

                db.Histories.Add(occurrence);
                db.SaveChanges();

                alog.InfoFormat("History created, Id={0}, Indicator={1}, Status={2}",
                    occurrence.HistoryId, occurrence.Initiator, occurrence.Status);
            }

            occurrence.Request = 0;
            occurrence.Latency = 0;
            occurrence.Payload = 0;
            occurrence.Inserted = 0;
            occurrence.Updated = 0;
            occurrence.Deleted = 0;
            occurrence.Error = 0;
        }

        public void Dispose()
        {
            using (var db = new MmContext())
            {
                var me = db.Histories.First(p => p.HistoryId == occurrence.HistoryId);
                {
                    me.Request = occurrence.Request;
                    me.Latency = occurrence.Latency;
                    me.Payload = occurrence.Payload;
                    me.Inserted = occurrence.Inserted;
                    me.Updated = occurrence.Updated;
                    me.Deleted = occurrence.Deleted;
                    me.Error = occurrence.Error;

                    me.End = DateTime.UtcNow;
                    me.Status = (me.Status == occurrence.Status ?
                        HistoryStatus.Finished.ToString() : occurrence.Status);
                }

                db.SaveChanges();

                alog.InfoFormat("History updated, Id={0}, Indicator={1}, Status={2}",
                    me.HistoryId, me.Initiator, me.Status);
            }
        }

        public void AddHttp(long latency, long payload)
        {
            lock (sync)
            {
                occurrence.Request++;
                occurrence.Latency += latency;
                occurrence.Payload += payload;
            }
        }

        public long GetCount()
        {
            throw new NotImplementedException();
        }

        public long GetLatency()
        {
            throw new NotImplementedException();
        }

        public long GetPayload()
        {
            throw new NotImplementedException();
        }

        public void Cancel()
        {
            lock (sync)
            {
                // only change status to cancel when current status is in processing
                if (occurrence.Status == HistoryStatus.InProcessing.ToString())
                {
                    occurrence.Status = HistoryStatus.Cancelled.ToString();
                }
            }
        }

        public void Fault()
        {
            lock (sync)
            {
                // only change status to fault when current status is in processing
                if (occurrence.Status == HistoryStatus.InProcessing.ToString())
                {
                    occurrence.Status = HistoryStatus.Faulted.ToString();
                }
            }
        }

        public void AddUpdated()
        {
            lock (sync)
            {
                occurrence.Updated++;
            }
        }

        public void AddInserted()
        {
            lock (sync)
            {
                occurrence.Inserted++;
            }
        }

        public void AddDeleted()
        {
            lock (sync)
            {
                occurrence.Deleted++;
            }
        }

        public void AddError()
        {
            lock (sync)
            {
                occurrence.Error++;
            }
        }


        private enum HistoryStatus
        {
            InProcessing,
            Finished,
            Cancelled,
            Faulted,
        }
    }
}